import numpy as np
import scipy.special as spec
import matplotlib.pyplot as plt
import os
import scipy.optimize as sp
from scipy.integrate import cumtrapz
import h5py

from qm.QuantumMachinesManager import QuantumMachinesManager
from qm import SimulationConfig
from qm import LoopbackInterface
from qm.qua import *
from qm.qua.math import cos, sin, cos2pi, sin2pi

from InstrumentsLibrary import *

# path='Z:\\SMPD_W3C5\\Run3_cycle2\\Spin_detection\\'
# path='Z:\\TbCaWO4\\Run1\\'
# path='Z:\\QMem\\20230403 KIC21E@bluefors4\\'
path = 'Z:\\SMPD3-8\\SpinRun3-1\\'

readout_element = 'Buffer'
readout_pulse = 'Buffer_readout'

# readout_pulse='Buffer_gaussian_pulse'
# readout_pulse='Buffer_readout_Gauss'

Buffer_VNA = 'Buffer_VNA'

ADC_pulse = 'ADC_pulse'

qubit_element = 'Qubit'
qubit_pulse = 'Qubit_control'
JPA_element = 'JPA'
JPA_pulse = 'JPA_pump'
photon_element = 'Photon'
spin_element = 'Spin'
ut_spin_element = 'Spin_untriggered'
spin_sticky_element = 'Spin_sticky'
spin_sticky_extra_element = 'Spin_sticky_extra'
spin_sticky_extra2_element = 'Spin_sticky_extra2'
spin_sticky4_element = 'Spin_sticky4'
spin_sticky5_element = 'Spin_sticky5'
spin_sticky6_element = 'Spin_sticky6'
spin_switch_element = 'Spin_switch'
fsv_trigger = 'FSV_switch'

spin_pulse = 'Spin_pulse'
spin_gauss_pulse = 'gauss_pulse'
spin_sticky_pulse = 'Spin_rising'
spin_cos_sticky_pulse = 'Spin_cos_rising'
spin_chirp_sticky_pulse = 'Spin_chirp_rising'
spin_chirp_sticky_pulse_down = 'Spin_chirp_lowering'
photon_pulse = 'Photon_pulse_in'
pump_element = 'Pump'
pump_pulse = 'Pump_pulse'

temp_fridge = 16.0  # mk
buffer_yoko_voltage = 9.96  # 910 Ohm load
jpa_yoko_voltage = 5.552  # 3kOhm load

I_threshold = -0.003e-4  # 1e-4#1.337e-4
I_threshold_reset = I_threshold

theta = 0.25 * np.pi  # 0.25*np.pi
# Buffer_freq = 7.99e9#7.9893e9#7.9889e9#7.99370e9#8.000e9#.00328e9#6.98427e9#6.9487e9
Buffer_freq = 8467.9e6  # 8465.2e6#8.483e9#8.48657e9 #7.422e9  # 6.61e9 # 8.131e9#7.9893e9#7.9889e9#7.99370e9#8.000e9#.00328e9#6.98427e9#6.9487e9

Buffer_IF = 50e6  # 0  #   # 100e6 #112.6e6
Buffer_LO = Buffer_freq - Buffer_IF

JPA_angle = 1.6 * np.pi
Buffer_angle = (4.956-0.022+0.24+0.585-0.844-0.038+0.324-0.017+0.043+0.017+0.02-0.057+0.022-0.056-0.04+0.057-0.498-0.148+0.616-0.487) * np.pi

Buffer_VNA_pulse_length = 5000  # for VNA-type  scans
Buffer_VNA_amp = 0.1  #

Buffer_att = 70
Buffer_readout_delay = 28 + 4 * int(350 / 4)  # +4*int(350/4) # 28 is the minimum, it has to be divisible by 4
Buffer_Gauss_amplitude = 0.2  # 0.07#*1.12*1.7*1.4 #*6#* 1.43 #0.4 #0.0366*2*2*1.64*1.95*1.12 #* 1.53
Buffer_Gauss_mu = 0
Buffer_Gauss_sigma = 400 * 2
Buffer_Gauss_length = 5 * Buffer_Gauss_sigma

spectro = False

if spectro:
    Buffer_readout_pulse_length = 10000  # 40000  #1600#1600 #10000 for VNA-type  scans
    Buffer_const_amp = 0.01  # 0.001#0.0005 #0.005#0.01#0.005 #0.1        # Starts to behave non linearly at 0.00005 or below
else:

    Buffer_readout_pulse_length = 1200  # 1000  #1600#1600 #10000 for VNA-type  scans
    # Buffer_const_amp = 0.075276936#0.32*1.5 #change buffer gaussian ampliude
    # Buffer_const_amp = 0.05*1.2*1.5*1.5*1.5*0.8*1.5*1.5*0.8#0.32*1.5 #change buffer gaussian ampliude
    Buffer_const_amp = 0.05 * 1.2 * 1.5 * 1.5 * 1.5 * 0.8 * 1.5 * 1.5 * 0.8 * 1.3 * 1.08 * 0.9 * 0.5 * 1. # 0.32*1.5 #change buffer gaussian ampliude

    # Buffer_readout_pulse_length = Buffer_Gauss_length  #1600#1600 #10000 for VNA-type  scans
    # Buffer_readout_delay =28+4*int(400/4)#+4*int(350/4) # 28 is the minimum, it has to be divisible by 4

ADC_length = 500 * 1e3

I0_Buffer = 0.01522
Q0_Buffer = 0.014
g_Buffer = -0.041
phi_Buffer = -0.05

## Photon element parameters ##
## 7.336515e9 detune photon counter 1MHz higher V = -2.773
Photon_freq = 7749105500# 7749215634-1.727e6-0.34e6-0.576e6+1.964e6+0.65e6-0.514e6+0.469e6-0.052e6+0.112e6#7750e6+0.493e6+0.245e6#7744.6e6-0.825e6+0.9e6#7749.2e6 - 1.842e6 - 0.748e6 # 7743770724-2e6-1.1e6 #7744596426 #7744598704 #7.729e9+0.271e6-0.043e6+0.340e6+0.270e6+0.527e6+18e6-200e3 #7.335350753e9# calib7.333412e9#  ##7.335359e9#7.33541e9#8.013e9#7029.837e6  #7029.102320e6  #7.01776e9                 ##7.146752e9###7.1345
Photon_IF = 100e6  # 1e8#100104451#100112698#100173478#99917362#99981824 - 8000#100e6
Photon_LO = Photon_freq + Photon_IF
# Photon_IF=104.77e6
## Photon_IF for test heating at BZ 427mT: 99653517

Photon_pulse_length = 15000  # 1600#1600 #10000 for VNA-type  scans
Photon_const_amp = 0.05 * 0.8 * 0.5 * 0.5 * 0.5 * 0.5 *0.7*1.4 #* 2 * 2 * 2 * 2 * 2 # 0.03*0.7#0.05#0.007#0.00001#0.005*0.6#*6#0.002#0.05#*0.1 #* 0.5    #0.15#0.08 #0.04

adiabatic_photon_sigma = 60
adiabatic_photon_amp = Photon_const_amp

Spin_pulse_length = 5000  # ns
Spin_const_amp = 0.1*0.054/0.037  # Keep smaller than 0.45

Spin_Gauss_sigma = 40  # ns
Spin_Gauss_amplitude = 0.15*0.054/0.037  # Keep smaller than 0.45

spin_detuning_extra = 100000

spin_chirp_amplitude = Spin_const_amp
spin_chirp_duration = 5000  # µs
spin_chirp_df = -0.12       # MHz

adiabatic_spin_sigma = 1600 # in ns
adiabatic_spin_Nsigma = 6
adiabatic_spin_amp = Spin_const_amp
switch_duration_extra = (adiabatic_spin_sigma*(adiabatic_spin_Nsigma+0.5)*2)//16*4  # Ensures this is a multiple of 4

I0_photon = -0.03653
Q0_photon = 0.0117

g_Photon = -0.051
phi_Photon = 0.087


#I0_photon = -0.0365
#Q0_photon = 0.012
#
#g_Photon = -0.051
#phi_Photon = 0.067

### Nuclear spin parameters ###

spacing = 40e3

# Sideband pulses parameters
N_preparation = 10
frequency_prep_blue = +0.755e6
frequency_prep_red  = -0.755e6
amplitude_prep_pulse = 0.31
flattop_prep_duration = 21000 // 4
t_wait_prep = 3000000 // 4

# Frequency selective pi pulse for readout
amplitude_RO_pulse = 0.011
duration_RO_pulse = 40000//4

#### Qubit element ####
Qubit_freq = 6.780745e9-0.022e6+0.136e6+0.145e6-1.11e6+0.259e6#6.78124e9 + 0.005e6 + 0.028e6 + 0.021e6 + 0.142e6 + 0.028e6 - 0.031e6 - 0.016e6 + 0.006e6 + 68e3  # 6.635e9#6.17286e9-72e3-72e3#6.168904e9#6.17126e9+1.5e6+0.037e6-512e3-71e3#6.12724e9#6.1805e9
Qubit_IF = 70e6
Qubit_LO = Qubit_freq + Qubit_IF

I0_Qubit = -0.0045
Q0_Qubit = -0.0041
g_Qubit = 0.05
phi_Qubit = -0.1
Qubit_control_length = 500  # 144 #4*int(393/4)#4*int(711/4)#10000 #10000 for qubit spectroscopy
Qubit_control_amplitude = 0.02 * 2 * 2 * 1.2 * 2  # 0.1553*1.01*1.55*1.042#0.02*1.116*1.114*1.359#0.002*1.116*1.114*1.359#0.3 #0.065*1.5*0.904
Qubit_const_amp = Qubit_control_amplitude
Qubit_control_mu = 0
Qubit_control_sigma = Qubit_control_length / 4
Qubit_pi_pulse_amp = 0.129*1.006
Qubit_pi2_pulse_amp = Qubit_pi_pulse_amp / 2

## Pump element
Pump_freq = 7.503e9+0.88e6-0.53e6-1.861e6+0.61e6-0.554e6-1.554e6-1e6-1.7e6+0.4e6+0.94e6-0.6e6+1.124e6-0.144e6+0.4e6-1.1e6+0.411e6+0.118e6-0.6e6+2.413e6-1.75e6-0.277e6#7500.0e6-1.4e6-0.46e6-1e6# Pump_IF = 163e6#150.12e6#145.73e6#150.00e6 #
Pump_IF = 200e6  # 199981824#200e6#200e6#234e6#229.87e6 #231.2e6
# Pump_LO=6665.37e6
Pump_LO = Pump_freq + Pump_IF  # Pump_LO=Pump_freq-Pump_IF
## Pump_IF for test heating at BZ 427mT: 199597725

Pump_pulse_length = 15000  # 8000
adiabatic_pump_amp = 0.099/np.sqrt(1)
adiabatic_pump_sigma = 60  # 60#60
Pump_const_amp = 0.2 * 0.6 * 0.3 * 0.3 * 1.572
I0_Pump = -0.0145  # -0.0132#0.00215#-0.013581
Q0_Pump = -0.00685  # -0.025#-0.02535#0.0042328
g_Pump = 0.0055  # 261
phi_Pump = -0.042  # 065#0.228



Waste_IF = 50e6
Waste_LO = 7.62e9 - 50e6
Waste_reset_pulse_length = 1000
Waste_const_amp = 0.2

JPA_pump_pulse_length = Buffer_readout_pulse_length + 200
JPA_const_amp = 0.  # *1.15#*0.62#*0.80 #0.86
I0_Paramp = 0.0065
Q0_Paramp = -0.0151
g_JPA = 0.0
phi_JPA = 0.01


### Raman preparation pulses parameters ###

spacing1 = 35.444 # in kHz
spacing2 = 22.661


nuclear_spin_freq_a_bare = int(808.777e3) + int(137)
nuclear_spin_freq_b_bare = int(810.46e3) + int(354)

nuclear_spin_freq_a_starckshift = -int(137)
nuclear_spin_freq_b_starckshift = -int(343)

nuclear_spin_freq_a_prep = nuclear_spin_freq_a_bare + nuclear_spin_freq_a_starckshift
nuclear_spin_freq_b_prep = nuclear_spin_freq_b_bare + nuclear_spin_freq_b_starckshift

raman_pi_half_duration_a_prep = int(1.085e6//4)  # in ns
raman_pi_half_duration_b_prep = int(1.86e6//4)  # in ns

raman_pi_duration_a_prep = int(3.14e6//4)  # in ns
raman_pi_duration_b_prep = int(4.80e6//4)  # in ns

detuned_electron_amplitude_a_prep = 0.025
detuned_electron_amplitude_b_prep = 0.05

detuned_sideband_amplitude_a_prep = 0.025
detuned_sideband_amplitude_b_prep = 0.05

raman_detuning_prep = -int(809.791e3/2)
ramp_time_prep      = int(1.2e6/4)

raman_detuning_a_prep = -int(809.791e3/2+36e3)
raman_detuning_b_prep = -int(809.791e3/2+35.5e3)

#### CNOT pulses #############
raman_detuning_cnot = 110e3
ramp_time_cnot       = int(0.6e6/4)

# flip B conditional on A
nuclear_spin_freq_cnot = int(810.227e3)
raman_pi_duration_cnot = int(7.5e6//4) # in ns

detuned_electron_amplitude_cnot = 0.02
detuned_sideband_amplitude_cnot = 0.1

# flip A conditional on B
nuclear_spin_freq_cnot_a = int(808.777e3)
raman_pi_duration_cnot_a = int(7.5e6//4) # in ns

detuned_electron_amplitude_cnot_a = 0.01
detuned_sideband_amplitude_cnot_a = 0.05

### Chirped sideband preparation parameters ###

chirped_pump_amplitude = 0.1
chirped_pump_duration = int(3_500_000//4)
chirped_pump_freq = Photon_IF - int(0.810e6)
chirp_rate = int(50/(chirped_pump_duration*4e-9))  # kHz/s
pump_steps_chirped = 50
pump_steps_after_tracking_prep = 50
pump_delay_chirped = int(2e6//4)

### SMPD preparation pulses parameters ###

waiting_time_SMPD_prep = 1000      # in ns
waiting_time_spin_prep = 120000//4 # in ns
waiting_after_spinreadout_prep = 100_000//4 # in ns
amplitude_readout_pulse_prep = 0.00237
gauss_duration_prep = 160_000//4      # frequency selective pi pulse
cycle_time_estimated_prep = 17  #in us Need to change this to something better
Integration_time_prep = 1200 #in us
N_readout_prep = int(Integration_time_prep/cycle_time_estimated_prep)  #30000

N_ROcycle_prep = 150
threshold_prep = 50

### Sideband nuclear spin a reset params ###
sb_pi_amplitude_prep = 0.1
sb_pi_duration_prep = int(120e3//4)
freq_sideband_prep_blue = int(Photon_IF - 0.7775e6)#- 0.774e6)
freq_sideband_prep_red = int(Photon_IF + 0.8e6)


#

Input1_Offset = -0.01  # 0.1195
Input2_Offset = -0.01  # -0.15

instruments = {'MWG':
    [
        {'name': 'cav',
         'instype': 'AnaPicoAPMS4Channel',
         'channel': 1,
         'load': True,
         'address': 'TCPIP::192.168.0.26',
         #  'address': 'USB-915-0M1040010-0058',
         'freqGHz': Buffer_LO * 1e-9,
         'power': 18,
         'state': 'ON',
         },

        {'name': 'qubit',
         'instype': 'AnaPicoAPMS4Channel',
         'channel': 2,
         'load': True,
         'address': 'TCPIP::192.168.0.26',
         'freqGHz': Qubit_LO * 1e-9,
         'power': 19,
         'state': 'ON',
         },

        {'name': 'photon',
         'instype': 'AnaPicoAPMS4Channel',
         'channel': 3,
         'load': True,
         'address': 'TCPIP::192.168.0.26',
         'freqGHz': Photon_LO * 1e-9,
         'power': 15,
         'state': 'ON',
         },

        {'name': 'pump',
         'instype': 'AnaPicoAPMS4Channel',
         'channel': 4,
         'load': True,
         'address': 'TCPIP::192.168.0.26',
         'freqGHz': Pump_LO * 1e-9,
         'power': 18,
         'state': 'ON',
         },
    ]
}

calibration_path = r".\weights_calibration"
try:
    with h5py.File(calibration_path + '/' + 'weights.h5', 'r') as f:
        I_weight = f['I_weight'][()]
        Q_weight = f['Q_weight'][()]
    print('Weights loaded')
except:
    I_weight = np.array([1.0] * int(Buffer_readout_pulse_length / 4))
    Q_weight = np.array([0.0] * int(Buffer_readout_pulse_length / 4))
    print('No weights calibration found')


##

def readout_block_Idual(readout_element, readout_pulse, I, readout_angle=Buffer_angle):

    reset_frame(readout_element)
    frame_rotation(readout_angle, readout_element)
    wait(20, readout_element)

    measure(readout_pulse, readout_element, None,
            dual_demod.full("integW_cos",  "out1", "integW_sin", "out2", I)
            )
    return I

def readout_block(readout_element, JPA_element, readout_pulse, JPA_pulse, I1, Q1, I2, Q2, I, Q, JPA_angle=JPA_angle,
                  Buffer_angle=Buffer_angle, ADC=None):
    reset_frame(readout_element)
    # reset_frame(JPA_element)
    # frame_rotation(JPA_angle, JPA_element)
    frame_rotation(Buffer_angle, readout_element)
    # play(JPA_pulse, JPA_element)
    wait(20, readout_element)

    measure(readout_pulse, readout_element, ADC,
            demod.full("integW_cos", I1, "out1"),
            demod.full("integW_sin", Q1, "out1"),
            demod.full("integW_cos", I2, "out2"),
            demod.full("integW_sin", Q2, "out2"))
    assign(I, I1 + Q2)
    assign(Q, -Q1 + I2)

    return I, Q


def readout_block_I(readout_element, JPA_element, readout_pulse, JPA_pulse, I1, Q2, I, JPA_angle=JPA_angle,
                    Buffer_angle=Buffer_angle):
    reset_frame(readout_element)
    # reset_frame(JPA_element)
    # frame_rotation(JPA_angle, JPA_element)
    frame_rotation(Buffer_angle, readout_element)
    # play(JPA_pulse, JPA_element)
    wait(20, readout_element)

    measure(readout_pulse, readout_element, None,
            demod.full("integW_cos", I1, "out1"),
            demod.full("integW_sin", Q2, "out2"))
    assign(I, I1 + Q2)
    return I


def IQ_imbalance_corr(g, phi):
    c = np.cos(phi)
    s = np.sin(phi)
    N = 1 / ((1 - g ** 2) * (2 * c ** 2 - 1))
    return [float(N * x) for x in [(1 - g) * c, (1 + g) * s,
                                   (1 - g) * s, (1 + g) * c]]


def gauss(amplitude, mu, sigma, length):
    t = np.linspace(-length / 2, length / 2, length)
    gauss_wave = amplitude * np.exp(-((t - mu) ** 2) / (2 * sigma ** 2))
    return [float(x) for x in gauss_wave]


def ErfSquarePulseHeight(numberOfPoints, start, stop, sigma, amplitude=1):
    """
    'Square' pulse with gaussian rise and fall, specified by its height
    """
    # start, stop, sigma = convertInPoints(samplingTime, start, stop, sigma)

    t = np.arange(numberOfPoints)

    values = amplitude * ((spec.erf((t - start - 2 * sigma) / sigma) + 1) / 2 - (
                spec.erf((t - stop + 2. * sigma) / sigma) + 1) / 2)
    # values =1

    return values


def ErfRising(numberOfPoints, sigma, amplitude=1):
    t = np.arange(numberOfPoints)
    values = amplitude * (spec.erf((t - numberOfPoints / 2) / sigma) + 1) / 2
    return values


def chirp_cos_raise(length, amp, df):
    t = np.linspace(0, length, abs(length))
    cosfunc = (1-np.cos(np.pi*t/length))/2
    phase = cumtrapz(df*(1-cosfunc**2), x=t, initial=0)
    return amp*cosfunc*np.cos(phase), amp*cosfunc*np.sin(phase)


config = {

    'version': 1,

    'controllers': {
        'con1': {
            'type': 'opx1',
            'analog_outputs': {
                1: {'offset': I0_Buffer},  # Buffer in I
                2: {'offset': Q0_Buffer},  # Buffer in Q
                3: {'offset': I0_photon},  # Photon in I
                4: {'offset': Q0_photon},  # Photon in Q
                5: {'offset': +0.0},
                6: {'offset': +0.0},  # Qubit in SSB
                7: {'offset': I0_Pump},
                8: {'offset': Q0_Pump},
                9: {'offset': 0},
                10: {'offset': 0},
            },
            'digital_outputs': {
                1: {},  # Digital trigger for Buffer and Paramp
                2: {},  # Digital trigger for Pump
                3: {},  # Digital trigger for Waste
                4: {},  # Digital trigger for Qubit
                5: {},  # Switch control: open and close spin line
                7: {},  # Trigger for the Spectrum Analyzer
            },
            'analog_inputs': {
                1: {'offset': Input1_Offset},  # Buffer I
                2: {'offset': Input2_Offset},  # Buffer Q
            },
        },
    },

    'elements': {

        'Buffer': {  # Buffer resonator element
            'mixInputs': {
                'I': ('con1', 1),  # 2
                'Q': ('con1', 2),  # 1
                'lo_frequency': Buffer_LO,
                'mixer': 'Buffer_mixer',
            },
            'intermediate_frequency': Buffer_IF,
            'operations': {
                'Buffer_continuous': 'Buffer_continuous_pulse',
                'Buffer_readout': 'Buffer_readout_pulse',
                'Buffer_readout_weighted': 'Buffer_readout_pulse_weighted',
                'Buffer_readout_Gauss': 'Buffer_gaussian_pulse',
                'Buffer_VNA': 'Buffer_VNA_pulse',
                'ADC_pulse': 'ADC_pulse',
            },
            'digitalInputs': {
                'switch_Buffer': {
                    # 'port': ('con1', 1), # to open the switch to the spin line: 'port': ('con1', 5),
                    'port': ('con1', 5),  # to open the switch to the spin line: 'port': ('con1', 5),
                    'delay': 104,
                    'buffer': 0,
                }
            },
            'outputs': {
                'out1': ('con1', 1),
                'out2': ('con1', 2),
            },
            'time_of_flight': Buffer_readout_delay,
            'smearing': 0,
        },

        'Photon': {  # Photon element, use the same chanels as Buffer, with same LO but different IF.
            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'operations': {
                'Photon_pulse_in': 'Photon_pulse',  # to open the switch to the spin line: 'port': ('con1', 5),
                'Photon_mixer_calib': 'Photon_mixer_calib_pulse',
                'ADC_pulse': 'ADC_pulse',
                'Spin_pulse': 'Spin_Square_pulse',
                'gauss_pulse': 'Spin_Gauss_pulse'
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 3),
                    'delay': 104,
                    'buffer': 0,
                }
            },

        },

        'Photon_sticky': {

            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'hold_offset': {'duration': 1000},
            'operations': {
                'Photon_rising': 'Photon_rising_pulse',
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 3),
                    'delay': 104,
                    'buffer': 0,
                }
            },
        },

        'Photon_switch': {  # fictious channel for controlling digital marker
            'singleInput': {
                'port': ('con1', 10),
            },
            'operations': {
                'ON': 'Photon_switch_ON',
                'OFF': 'Photon_switch_OFF',
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 3),
                    'delay': 104,
                    'buffer': 0,
                }
            },
        },

        'Spin': {  # Photon element, use the same chanels as Buffer, with same LO but different IF.
            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'operations': {
                # 'Photon_pulse_in': 'Photon_pulse',
                'Spin_pulse': 'Spin_Square_pulse',
                'gauss_pulse': 'Spin_Gauss_pulse'
            },
            'digitalInputs': {
                'switch_spin': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },

        },



        'Spin_sticky': {

            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },

            'intermediate_frequency': Photon_IF,
            'hold_offset': {'duration': 50000},
            'operations': {
                'Spin_rising': 'Spin_rising_pulse',
                'Spin_cos_rising': 'Spin_cos_rising_pulse',
                'Spin_chirp_rising': 'Spin_chirp_rising_pulse',
                'Spin_chirp_lowering': 'Spin_chirp_lowering_pulse'
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },
        },



        'Spin_sticky_extra': {

            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'hold_offset': {'duration': 50000},
            'operations': {
                'Spin_rising': 'Spin_rising_pulse',
                'Spin_cos_rising': 'Spin_cos_rising_pulse',
                'Spin_chirp_rising': 'Spin_chirp_rising_pulse',
                'Spin_chirp_lowering': 'Spin_chirp_lowering_pulse'
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },
        },

        'Spin_sticky_extra2': {

            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'hold_offset': {'duration': 50000},
            'operations': {
                'Spin_rising': 'Spin_rising_pulse',
                'Spin_cos_rising': 'Spin_cos_rising_pulse',
                'Spin_chirp_rising': 'Spin_chirp_rising_pulse',
                'Spin_chirp_lowering': 'Spin_chirp_lowering_pulse'
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },
        },

        'Spin_sticky4': {

            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'hold_offset': {'duration': 50000},
            'operations': {
                'Spin_rising': 'Spin_rising_pulse',
                'Spin_cos_rising': 'Spin_cos_rising_pulse',
                'Spin_chirp_rising': 'Spin_chirp_rising_pulse',
                'Spin_chirp_lowering': 'Spin_chirp_lowering_pulse'
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },
        },

        'Spin_sticky5': {

            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'hold_offset': {'duration': 50000},
            'operations': {
                'Spin_rising': 'Spin_rising_pulse',
                'Spin_cos_rising': 'Spin_cos_rising_pulse',
                'Spin_chirp_rising': 'Spin_chirp_rising_pulse',
                'Spin_chirp_lowering': 'Spin_chirp_lowering_pulse'
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },
        },

        'Spin_sticky6': {

            'mixInputs': {
                'I': ('con1', 3),
                'Q': ('con1', 4),
                'lo_frequency': Photon_LO,
                'mixer': 'Photon_mixer',
            },
            'intermediate_frequency': Photon_IF,
            'hold_offset': {'duration': 50000},
            'operations': {
                'Spin_rising': 'Spin_rising_pulse',
                'Spin_cos_rising': 'Spin_cos_rising_pulse',
                'Spin_chirp_rising': 'Spin_chirp_rising_pulse',
                'Spin_chirp_lowering': 'Spin_chirp_lowering_pulse'
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },
        },

        'Spin_switch': {  # fictious channel for controlling digital marker
            'singleInput': {
                'port': ('con1', 10),
            },
            'operations': {
                'ON': 'Photon_switch_ON',
                'OFF': 'Photon_switch_OFF',
            },
            'digitalInputs': {
                'switch_Photon': {
                    'port': ('con1', 1),
                    'delay': 104,
                    'buffer': 0,
                },
            },
        },


        'FSV_switch': {  # Channel that just triggers the Spectrum analyzer
            'singleInput': {
                'port': ('con1', 10),
            },
            'operations': {
                'ON': 'Photon_switch_ON',
                'OFF': 'Photon_switch_OFF',
            },
            'digitalInputs': {
                'trigger_marker_extra': {
                    'port': ('con1', 7),
                    'delay': 104,
                    'buffer': 0,
                }
            },
        },


        'Pump': {  # Pump element to send pump pulses to qubit
            'mixInputs': {
                'I': ('con1', 7),
                'Q': ('con1', 8),
                'lo_frequency': Pump_LO,
                'mixer': 'Pump_mixer',
            },
            'intermediate_frequency': Pump_IF,
            'operations': {
                'Pump_pulse': 'Pump_conversion_pulse',
                'Pump_continuous': 'Pump_continuous_pulse',
                'Pump_mixer_calib': 'Pump_mixer_calib_pulse',
            },
            'digitalInputs': {
                'switch_Pump': {
                    'port': ('con1', 2),
                    'delay': 104,
                    'buffer': 0,
                }
            },
        },

        'Pump_sticky': {
            'mixInputs': {
                'I': ('con1', 10),
                'Q': ('con1', 9),
                'lo_frequency': Pump_LO,
                'mixer': 'Pump_mixer',
            },
            'intermediate_frequency': Pump_IF,
            'hold_offset': {'duration': 1000},
            'operations': {
                'Pump_rising': 'Pump_rising_pulse',
            },
            'digitalInputs': {
                'switch_Pump': {
                    'port': ('con1', 2),
                    'delay': 104,
                    'buffer': 0,
                }
            },
        },

        'Waste': {  # Waste resonator element
            'singleInput': {
                'port': ('con1', 5),
            },
            'intermediate_frequency': Waste_IF,
            'operations': {
                'Waste_reset': 'Waste_reset_pulse',
            },
            'digitalInputs': {
                'switch': {
                    'port': ('con1', 3),
                    'delay': 104,
                    'buffer': 0,
                }
            },
        },

        'Qubit': {  # Qubit element, SSB mixer, for applying pulses to the qubit during qubit spectroscopy
            'singleInput': {
                'port': ('con1', 6),
            },
            'intermediate_frequency': Qubit_IF,
            'operations': {
                'Qubit_control': 'Qubit_control_pulse',
                'Qubit_control_simple': 'Qubit_control_simple_pulse',
                'Qubit_continuous': 'Qubit_continuous_pulse',
            },
            'digitalInputs': {
                'switch': {
                    'port': ('con1', 4),
                    'delay': 104,
                    'buffer': 0,
                }
            },
        },

        # 'Qubit': {  # Qubit element, IQ mixer
        #     'mixInputs': {
        #         'I': ('con1', 3),
        #         'Q': ('con1', 4),
        #         'lo_frequency': Qubit_LO,
        #         'mixer': 'Qubit_mixer',
        #     },
        #     'intermediate_frequency': Qubit_IF,
        #     'operations': {
        #         'Qubit_continuous': 'Qubit_continuous_pulse',
        #         'Qubit_control': 'Qubit_control_pulse',
        #         'Qubit_control_simple': 'Qubit_control_simple_pulse',
        #     },
        #     'digitalInputs': {
        #         'switch': {
        #             'port': ('con1', 4),
        #             'delay': 144,
        #             'buffer': 0,
        #         }
        #     },
        # },

        'JPA': {  # JPA element, for pumping the Josephson Parametric Amplifier at double the buffer frequency
            'mixInputs': {
                'I': ('con1', 7),
                'Q': ('con1', 8),
                'lo_frequency': Buffer_LO * 2,
                'mixer': 'JPA_mixer',
            },
            'intermediate_frequency': Buffer_IF * 2,
            'operations': {
                'JPA_pump': 'JPA_pump_pulse',
            },
            'digitalInputs': {
                'switch_Pump': {
                    'port': ('con1', 1),
                    'delay': 144,
                    'buffer': 0,
                }
            },
        },
    },

    'pulses': {
        'Buffer_readout_pulse': {
            'operation': 'measurement',
            'length': Buffer_readout_pulse_length,
            'waveforms': {
                'I': 'constant_Buffer_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
            'integration_weights': {
                'integW_cos': 'integW_cosine',
                'integW_sin': 'integW_sine',
                'integW_minus_sin': 'integW_minus_sine',
            },
            'digital_marker': 'ON',
        },

        'Buffer_readout_pulse_weighted': {
            'operation': 'measurement',
            'length': Buffer_readout_pulse_length,
            'waveforms': {
                'I': 'constant_Buffer_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
            'integration_weights': {
                'integV1': 'integV1_weighted',
                'integV2': 'integV2_weighted',
            },
            'digital_marker': 'ON',
        },
        'Buffer_continuous_pulse': {
            'operation': 'measurement',
            'length': Buffer_readout_pulse_length,
            'waveforms': {
                'I': 'constant_Buffer_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
            'integration_weights': {
                'integW_cos': 'integW_cosine',
                'integW_sin': 'integW_sine',
            },
            'digital_marker': 'ON',
        },

        'Buffer_gaussian_pulse': {
            'operation': 'measurement',
            'length': Buffer_Gauss_length,
            'waveforms': {
                'I': 'gauss_Buffer_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
            'integration_weights': {
                'integW_cos': 'integW_cosine',
                'integW_sin': 'integW_sine',
            },
            'digital_marker': 'ON',
        },

        'Buffer_VNA_pulse': {
            'operation': 'measurement',
            'length': Buffer_VNA_pulse_length,
            'waveforms': {
                'I': 'constant_buffer_VNA_wf',
                'Q': 'zero_wf',
            },
            'integration_weights': {
                'integW_cos': 'integW_cosine',
                'integW_sin': 'integW_sine',
            },
            'digital_marker': 'ON',
        },

        'ADC_pulse': {
            'operation': 'measurement',
            'length': ADC_length,
            'waveforms': {
                'I': 'zero_wf',
                'Q': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Photon_pulse': {
            'operation': 'control',
            'length': Photon_pulse_length,
            'waveforms': {
                'I': 'constant_Photon_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
            'digital_marker': 'ON',
        },

        'Photon_switch_ON': {
            'operation': 'control',
            'length': 40,
            'waveforms': {
                'single': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Photon_switch_OFF': {
            'operation': 'control',
            'length': 40,
            'waveforms': {
                'single': 'zero_wf',
            },
            'digital_marker': 'OFF',
        },

        'Photon_rising_pulse': {
            'operation': 'control',
            'length': 6 * adiabatic_photon_sigma,
            'waveforms': {
                'I': 'rising_photon_wf',
                'Q': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Spin_Square_pulse': {
            'operation': 'control',
            'length': Spin_pulse_length,
            'waveforms': {
                'I': 'constant_Spin_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
            'digital_marker': 'ON',
        },

        'Spin_Gauss_pulse': {
            'operation': 'control',
            'length': 6 * Spin_Gauss_sigma,
            'waveforms': {
                'I': 'gauss_Spin_wf',
                'Q': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Spin_rising_pulse': {
            'operation': 'control',
            'length': adiabatic_spin_Nsigma * adiabatic_spin_sigma,
            'waveforms': {
                'I': 'rising_spin_wf',
                'Q': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Spin_cos_rising_pulse': {
            'operation': 'control',
            'length': spin_chirp_duration,
            'waveforms': {
                'I': 'rising_cos_spin_wf',
                'Q': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Spin_chirp_rising_pulse': {
            'operation': 'control',
            'length': spin_chirp_duration,
            'waveforms': {
                'I': 'rising_spin_chirp_wf_I',
                'Q': 'rising_spin_chirp_wf_Q',
            },
            'digital_marker': 'ON',
        },
        'Spin_chirp_lowering_pulse': {
            'operation': 'control',
            'length': spin_chirp_duration,
            'waveforms': {
                'I': 'lowering_spin_chirp_wf_I',
                'Q': 'lowering_spin_chirp_wf_Q',
            },
            'digital_marker': 'ON',
        },

        'Pump_conversion_pulse': {
            'operation': 'control',
            'length': Pump_pulse_length,
            'waveforms': {
                'I': 'adiabatic_pump_wf',
                'Q': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Pump_rising_pulse': {
            'operation': 'control',
            'length': 6 * adiabatic_pump_sigma,
            'waveforms': {
                'I': 'rising_pump_wf',
                'Q': 'zero_wf',
            },
            'digital_marker': 'ON',
        },

        'Waste_reset_pulse': {
            'operation': 'control',
            'length': Waste_reset_pulse_length,
            'waveforms': {
                'single': 'constant_waste_wf',
            },
            'digital_marker': 'ON',
        },

        'Qubit_continuous_pulse': {
            'operation': 'control',
            'length': Qubit_control_length,
            'waveforms': {
                'single': 'constant_Qubit_wf',
            },
            'digital_marker': 'ON',
        },

        'Qubit_control_pulse': {
            'operation': 'control',
            'length': Qubit_control_length,
            'waveforms': {
                'single': 'Qubit_control_wf',
            },
            'digital_marker': 'ON',
        },

        'Qubit_control_simple_pulse': {
            'operation': 'control',
            'length': Qubit_control_length,
            'waveforms': {
                'single': 'Qubit_control_simple_wf',
            },
            'digital_marker': 'ON',
        },

        'Qubit_control_gaussian_pulse': {
            'operation': 'control',
            'length': Qubit_control_length,
            'waveforms': {
                'single': 'Qubit_control_simple_wf',
            },
            'digital_marker': 'ON',
        },

        'JPA_pump_pulse': {
            'operation': 'control',
            'length': JPA_pump_pulse_length,
            'waveforms': {
                'I': 'JPA_pump_wf',
                'Q': 'zero_wf'
            },
            'digital_marker': 'ON',
        },
        'Pump_continuous_pulse': {
            'operation': 'control',
            'length': Pump_pulse_length,
            'waveforms': {
                'I': 'constant_Pump_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
            'integration_weights': {
                'integW_cos': 'integW_cosine',
                'integW_sin': 'integW_sine',
            },
            'digital_marker': 'ON',
        },
        'Photon_mixer_calib_pulse': {
            'operation': 'measurement',
            'length': Buffer_readout_pulse_length,
            'waveforms': {
                'I': 'constant_Photon_wf',
                # 'I': 'zero_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },

            # 'integration_weights': {
            #     'integW_cos': 'integW_cosine',
            #     'integW_sin': 'integW_sine',
            #  },
            'digital_marker': 'ON',
        },
        'Pump_mixer_calib_pulse': {
            'operation': 'measurement',
            'length': Pump_pulse_length,
            'waveforms': {
                'I': 'constant_Pump_wf',
                # 'I': 'zero_wf',
                'Q': 'zero_wf',
                # play('Buffer_readout'*amp([a,b,c,d]),'Buffer')   /   Pulse --> amp(x) --> upconversion (to IF) --> mixer_correction_matrix --> output
            },
        },
    },

    'waveforms': {

        'constant_Buffer_wf': {
            'type': 'constant',
            'sample': Buffer_const_amp,
        },

        'constant_Photon_wf': {
            'type': 'constant',
            'sample': Photon_const_amp,
        },

        'rising_photon_wf': {
            'type': 'arbitrary',
            'samples': ErfRising(6 * adiabatic_photon_sigma, adiabatic_photon_sigma, adiabatic_photon_amp)
        },

        'constant_Spin_wf': {
            'type': 'constant',
            'sample': Spin_const_amp,
        },
        'gauss_Spin_wf': {
            'type': 'arbitrary',
            'samples': gauss(Spin_Gauss_amplitude, 0, Spin_Gauss_sigma, 6 * Spin_Gauss_sigma)
        },

        'rising_spin_wf': {
            'type': 'arbitrary',
            'samples': ErfRising(adiabatic_spin_Nsigma * adiabatic_spin_sigma, adiabatic_spin_sigma, adiabatic_spin_amp)
        },

        'rising_cos_spin_wf': {
            'type': 'arbitrary',
            'samples': chirp_cos_raise(spin_chirp_duration, spin_chirp_amplitude, 0)[0]
        },

        'rising_spin_chirp_wf_I': {
            'type': 'arbitrary',
            'samples': chirp_cos_raise(spin_chirp_duration, spin_chirp_amplitude, spin_chirp_df)[0]
        },
        'rising_spin_chirp_wf_Q': {
            'type': 'arbitrary',
            'samples': chirp_cos_raise(spin_chirp_duration, spin_chirp_amplitude, spin_chirp_df)[1]
        },
        'lowering_spin_chirp_wf_I': {
            'type': 'arbitrary',
            'samples': chirp_cos_raise(spin_chirp_duration, spin_chirp_amplitude, spin_chirp_df)[0][::-1]-1*chirp_cos_raise(spin_chirp_duration, spin_chirp_amplitude, spin_chirp_df)[0][::-1][0]
        },
        'lowering_spin_chirp_wf_Q': {
            'type': 'arbitrary',
            'samples': chirp_cos_raise(spin_chirp_duration, spin_chirp_amplitude, spin_chirp_df)[1][::-1]-1*chirp_cos_raise(spin_chirp_duration, spin_chirp_amplitude, spin_chirp_df)[1][::-1][0]
        },

        'constant_Pump_wf': {
            'type': 'constant',
            'sample': Pump_const_amp,
        },

        'erf_Buffer_wf': {
            'type': 'arbitrary',
            'samples': ErfSquarePulseHeight(Buffer_readout_pulse_length, 0, 800, 50, Buffer_const_amp),
        },

        'zero_wf': {
            'type': 'constant',
            'sample': 0.0,
        },

        'constant_Qubit_wf': {
            'type': 'constant',
            'sample': Qubit_const_amp,
        },

        'adiabatic_pump_wf': {
            'type': 'arbitrary',
            'samples': ErfSquarePulseHeight(Pump_pulse_length, 0, Pump_pulse_length, adiabatic_pump_sigma,
                                            adiabatic_pump_amp)
        },

        'rising_pump_wf': {
            'type': 'arbitrary',
            'samples': ErfRising(6 * adiabatic_pump_sigma, adiabatic_pump_sigma, adiabatic_pump_amp)
        },

        'constant_waste_wf': {
            'type': 'constant',
            'sample': Waste_const_amp,
        },

        'Qubit_control_wf': {
            'type': 'arbitrary',
            'samples': gauss(Qubit_pi_pulse_amp, Qubit_control_mu, Qubit_control_sigma, Qubit_control_length)
            # gauss(Qubit_control_amplitude, Qubit_control_mu, Qubit_control_sigma, Qubit_control_length)
        },

        'gauss_Buffer_wf': {
            'type': 'arbitrary',
            'samples': gauss(Buffer_Gauss_amplitude, Buffer_Gauss_mu, Buffer_Gauss_sigma, Buffer_Gauss_length)
        },

        'constant_buffer_VNA_wf': {
            'type': 'constant',
            'sample': Buffer_VNA_amp,
        },

        'Qubit_control_simple_wf': {
            'type': 'constant',
            'sample': Qubit_const_amp
        },

        'JPA_pump_wf': {
            'type': 'constant',
            'sample': JPA_const_amp,
        },
    },

    'digital_waveforms': {
        'ON': {
            'samples': [(1, 0)]
            # [(value, length)] # [(value, length)] this should be absolutely put  to [(1,0)] if we want to acquire raw data (not for demod data)
        },  # NB: 0 means marker on for the whole duration of the pulse
        'OFF': {
            'samples': [(0, 0)]  # [(value, length)]
        },
    },

    'integration_weights': {

        'integW_cosine': {
            'cosine': [1.0] * int(Buffer_readout_pulse_length / 4),
            'sine': [0.0] * int(Buffer_readout_pulse_length / 4),
        },

        'integW_sine': {
            'cosine': [0.0] * int(Buffer_readout_pulse_length / 4),
            'sine': [1.0] * int(Buffer_readout_pulse_length / 4),
        },


        'integW_minus_sine': {
            'cosine': [0.0] * int(Buffer_readout_pulse_length / 4),
            'sine': [-1.0] * int(Buffer_readout_pulse_length / 4),
        },

        'integV1_weighted': {
            'cosine': I_weight,
            'sine': -Q_weight,  # -Q_weight, for reversed Wif
        },

        'integV2_weighted': {
            'cosine': Q_weight,
            'sine': I_weight,  # -I_weight, for reversed Wif
        },
    },

    'mixers': {
        'Buffer_mixer': [
            {'intermediate_frequency': Buffer_IF,
             'lo_frequency': Buffer_LO,
             'correction': IQ_imbalance_corr(g_Buffer, phi_Buffer)},

        ],

        'Photon_mixer': [
            {'intermediate_frequency': Photon_IF,
             'lo_frequency': Photon_LO,
             'correction': IQ_imbalance_corr(g_Photon, phi_Photon)},
        ],

        'Qubit_mixer': [
            {'intermediate_frequency': Qubit_IF,
             'lo_frequency': Qubit_LO,
             'correction': IQ_imbalance_corr(g_Qubit, phi_Qubit)},

        ],
        'Pump_mixer': [
            {'intermediate_frequency': Pump_IF,
             'lo_frequency': Pump_LO,
             'correction': IQ_imbalance_corr(g_Pump, phi_Pump)},
        ],

        'JPA_mixer': [
            {'intermediate_frequency': Buffer_IF * 2,
             'lo_frequency': Buffer_LO * 2,
             'correction': IQ_imbalance_corr(g_JPA, phi_JPA)}
        ],

    }

}

#### ERROR CHECKING #####

if Spin_const_amp > 0.45:
    pass
    # raise ValueError("Spin_const_amp is larger than 0.45, the OPX will not behave correctly beyond this limit")

